package climit

import (
	"os"
	"strconv"
)

// ================================== commandDefinition =============================================
type commandDefinition struct {
	name             string
	description      string
	expressions      map[string]*expressionDefinition
	options          []*optionDefinition
	shortNameOptions map[string]*optionDefinition
	longNameOptions  map[string]*optionDefinition
	run              func(commandDescriptor CommandDescriptor)
	subCommands      map[string]*commandDefinition
}

func newCommandDefinition() *commandDefinition {
	return &commandDefinition{
		expressions:      make(map[string]*expressionDefinition),
		options:          make([]*optionDefinition, 0),
		shortNameOptions: map[string]*optionDefinition{},
		longNameOptions:  map[string]*optionDefinition{},
		subCommands:      make(map[string]*commandDefinition),
	}
}

func newRootCommandDefinition(command *RootCommand) *commandDefinition {
	if command.Run == nil {
		panic("命令运行函数Run没有提供，命令将无法执行")
	}
	cd := newCommandDefinition()
	cd.description = command.Description
	cd.run = command.Run
	// 处理选项
	cd.addOptions(command.Options)
	// 处理表达式
	cd.addExpressions(command.Expressions)
	// 处理子命令
	for _, subCommand := range command.SubCommands {
		cd.addSubCommand(newSubCommandDefinition(&subCommand))
	}
	return cd
}

func newSubCommandDefinition(command *Command) *commandDefinition {
	if command.Run == nil {
		panic(command.Name + "命令运行函数Run没有提供，命令将无法执行")
	}
	cd := newCommandDefinition()
	cd.name = command.Name
	cd.description = command.Description
	cd.run = command.Run
	// 处理选项
	cd.addOptions(command.Options)
	// 处理表达式
	cd.addExpressions(command.Expressions)
	// 处理子命令, 因为目前子命令不支持子命令，所以暂不处理
	//for _, subCommand := range command.SubCommands {
	//	cd.addSubCommand(newSubCommandDefinition(&subCommand))
	//}
	return cd
}

func (receiver *commandDefinition) addExpression(expression *expressionDefinition) {
	if len(expression.getName()) == 0 {
		panic("表达式名称不能为空")
	}

	if len(expression.getName()) < 2 {
		panic("表达式的名称(" + expression.getName() + ")至少包含两个字符")
	}

	if _, ok := receiver.expressions[expression.getName()]; ok {
		panic("表达式名称(" + expression.getName() + ")重复")
	}

	// 检查表达式的默认值
	if len(expression.getDefaultValue()) > 0 {
		msg, ok := expression.checkValue(expression.getDefaultValue())
		if !ok {
			panic("表达式默认值校验不通过：" + msg)
		}
	}

	receiver.expressions[expression.getName()] = expression
}

// 添加选项
func (receiver *commandDefinition) addOption(option *optionDefinition) {
	if len(option.getLongName()) == 0 && len(option.getShortName()) == 0 {
		panic("选项的长名称和短名称至少提供一个")
	}
	if len(option.getShortName()) > 1 {
		panic("选项短名称(" + option.getShortName() + ")只能包含一个字符(如果提供的话)")
	}

	if len(option.getLongName()) > 0 && len(option.getLongName()) < 2 {
		panic("选项长名称(" + option.getLongName() + ")至少包含两个字符(如果提供的话)")
	}

	if _, ok := receiver.longNameOptions[option.getLongName()]; ok {
		panic("选项长名称(" + option.getLongName() + ")重复")
	}

	if _, ok := receiver.shortNameOptions[option.getShortName()]; ok {
		panic("选项短名称(" + option.getShortName() + ")重复")
	}
	if len(option.getDefaultValue()) > 0 {
		msg, ok := option.checkValue(option.getDefaultValue())
		if !ok {
			panic("选项默认值校验不通过：" + msg)
		}
	}

	if len(option.getShortName()) == 1 {
		receiver.shortNameOptions[option.getShortName()] = option
	}

	if len(option.getLongName()) > 1 {
		receiver.longNameOptions[option.getLongName()] = option
	}

	receiver.options = append(receiver.options, option)
}

func (receiver *commandDefinition) getOptionDefinition(optionName string) (*optionDefinition, bool) {
	if len(optionName) == 0 {
		panic("请提供选项名称")
	}
	if len(optionName) == 1 {
		definition, ok := receiver.shortNameOptions[optionName]
		return definition, ok
	}
	definition, ok := receiver.longNameOptions[optionName]
	return definition, ok
}

func (receiver *commandDefinition) getAllOptionDefinition() []*optionDefinition {
	return receiver.options
}

func (receiver *commandDefinition) getAllOptionNameSet() Set[string] {
	result := MakeSet[string]()
	if len(receiver.options) > 0 {
		for _, definition := range receiver.options {
			if len(definition.getLongName()) > 0 {
				result.Add(definition.getLongName())
			}
			if len(definition.getShortName()) > 0 {
				result.Add(definition.getShortName())
			}
		}
	}
	return result
}

func (receiver *commandDefinition) getAllExpressionDefinition() []*expressionDefinition {
	if len(receiver.expressions) == 0 {
		return make([]*expressionDefinition, 0)
	}
	values := make([]*expressionDefinition, 0, len(receiver.expressions)) // 预分配切片容量
	for _, v := range receiver.expressions {
		values = append(values, v)
	}
	return values
}

func (receiver *commandDefinition) getExpressionDefinition(expressionName string) (*expressionDefinition, bool) {
	if len(expressionName) == 0 {
		panic("请提供表达式名称")
	}
	if len(expressionName) == 1 {
		panic("表达式名称不合法，表达式名称至少包含两个字符")
	}
	definition, ok := receiver.expressions[expressionName]
	return definition, ok
}

func (receiver *commandDefinition) getAllExpressionNameSet() Set[string] {
	result := MakeSet[string]()
	if len(receiver.expressions) > 0 {
		for _, definition := range receiver.expressions {
			if len(definition.getName()) > 0 {
				result.Add(definition.getName())
			}
		}
	}
	return result
}

func (receiver *commandDefinition) addSubCommand(command *commandDefinition) {
	if len(command.name) == 0 {
		panic("子命令名称不能为空")
	}
	if _, ok := receiver.subCommands[command.name]; ok {
		panic("子命令名称(" + command.name + ")重复")
	}
	if command.run == nil {
		panic("子命令(" + command.name + ")的run函数不能为空")
	}
	receiver.subCommands[command.name] = command
}

func (receiver *commandDefinition) getSubCommandDefinition(subCommandName string) (*commandDefinition, bool) {
	if len(subCommandName) == 0 {
		panic("请提供子命令名称")
	}
	definition, ok := receiver.subCommands[subCommandName]
	return definition, ok
}

func (receiver *commandDefinition) execute() {
	parseCommandDefinition(os.Args, receiver, "").execute()
}

func (receiver *commandDefinition) addOptions(options []Option) {
	for _, op := range options {
		switch option := op.(type) {
		case BoolOption:
			receiver.addOption(newBoolOption(&option))
		case OptionalStringOption:
			receiver.addOption(newOptionalStringOption(&option))
		case RequiredStringOption:
			receiver.addOption(newRequiredStringOption(&option))
		case OptionalIntOption:
			receiver.addOption(newOptionalIntOption(&option))
		case RequiredIntOption:
			receiver.addOption(newRequiredIntOption(&option))
		case OptionalFloatOption:
			receiver.addOption(newOptionalFloatOption(&option))
		case RequiredFloatOption:
			receiver.addOption(newRequiredFloatOption(&option))
		default:
			panic("未知的参数类型")
		}
	}
}

func (receiver *commandDefinition) addExpressions(expressions []Expression) {
	for _, ep := range expressions {
		switch expression := ep.(type) {
		case RequiredExpression:
			receiver.addExpression(newRequiredExpressionDefinition(&expression))
		case OptionalExpression:
			receiver.addExpression(newOptionalExpressionDefinition(&expression))
		}
	}
}

// ================================== optionDefinition =============================================

type optionDefinition struct {
	shortName    string
	longName     string
	description  string
	defaultValue string
	valueType    string
	required     bool
	valueChecker func(string) (string, bool)
}

func newBoolOption(option *BoolOption) *optionDefinition {
	return &optionDefinition{
		shortName:    option.ShortName,
		longName:     option.LongName,
		description:  option.Description,
		defaultValue: "false",
		valueType:    "bool",
		required:     false,
	}
}

func newRequiredIntOption(option *RequiredIntOption) *optionDefinition {
	result := &optionDefinition{
		shortName:    option.ShortName,
		longName:     option.LongName,
		description:  option.Description,
		defaultValue: "",
		valueType:    "int",
		required:     true,
	}
	result.valueChecker = createIntOptionValueChecker(option.Range, result)
	return result
}

func newOptionalIntOption(option *OptionalIntOption) *optionDefinition {
	result := &optionDefinition{
		shortName:    option.ShortName,
		longName:     option.LongName,
		description:  option.Description,
		defaultValue: strconv.FormatInt(option.DefaultValue, 10),
		valueType:    "int",
		required:     false,
	}
	result.valueChecker = createIntOptionValueChecker(option.Range, result)
	return result
}

func newRequiredFloatOption(option *RequiredFloatOption) *optionDefinition {
	result := &optionDefinition{
		shortName:    option.ShortName,
		longName:     option.LongName,
		description:  option.Description,
		defaultValue: "",
		valueType:    "float",
		required:     true,
	}
	result.valueChecker = createFloatOptionValueChecker(option.Range, result)
	return result
}

func newOptionalFloatOption(option *OptionalFloatOption) *optionDefinition {
	result := &optionDefinition{
		shortName:    option.ShortName,
		longName:     option.LongName,
		description:  option.Description,
		defaultValue: strconv.FormatFloat(option.DefaultValue, 'f', -1, 64),
		valueType:    "float",
		required:     false,
	}
	result.valueChecker = createFloatOptionValueChecker(option.Range, result)
	return result
}

func newRequiredStringOption(option *RequiredStringOption) *optionDefinition {
	return &optionDefinition{
		shortName:    option.ShortName,
		longName:     option.LongName,
		description:  option.Description,
		defaultValue: "",
		valueType:    "string",
		required:     true,
		valueChecker: option.ValueChecker,
	}
}

func newOptionalStringOption(option *OptionalStringOption) *optionDefinition {
	return &optionDefinition{
		shortName:    option.ShortName,
		longName:     option.LongName,
		description:  option.Description,
		defaultValue: option.DefaultValue,
		valueType:    "string",
		required:     false,
		valueChecker: option.ValueChecker,
	}
}

func (receiver *optionDefinition) getShortName() string {
	return receiver.shortName
}

func (receiver *optionDefinition) getLongName() string {
	return receiver.longName
}

func (receiver *optionDefinition) getDescription() string {
	return receiver.description
}

func (receiver *optionDefinition) isBool() bool {
	return receiver.valueType == "bool"
}

func (receiver *optionDefinition) isRequired() bool {
	return receiver.required
}

func (receiver *optionDefinition) getDefaultValue() string {
	return receiver.defaultValue
}

func (receiver *optionDefinition) getKetch() string {
	return "选项(shortName=" + receiver.shortName + ",LongName=" + receiver.longName + ", valueType=" + receiver.valueType + ")"
}

func (receiver *optionDefinition) checkValue(value string) (string, bool) {
	if receiver.valueChecker != nil {
		msg, ok := receiver.valueChecker(value)
		if !ok {
			return receiver.getKetch() + "选项值校验失败: " + msg, false
		} else {
			return msg, true
		}
	} else {
		return "", true
	}
}

// ================================== expressionDefinition =============================================
type expressionDefinition struct {
	name         string
	description  string
	required     bool
	defaultValue string
	valueChecker func(string) (string, bool)
}

func newOptionalExpressionDefinition(expression *OptionalExpression) *expressionDefinition {
	return &expressionDefinition{
		name:         expression.Name,
		description:  expression.Description,
		required:     false,
		defaultValue: expression.DefaultValue,
		valueChecker: expression.ValueChecker,
	}
}

func newRequiredExpressionDefinition(expression *RequiredExpression) *expressionDefinition {
	return &expressionDefinition{
		name:         expression.Name,
		description:  expression.Description,
		required:     true,
		defaultValue: "",
		valueChecker: expression.ValueChecker,
	}
}

func (receiver *expressionDefinition) getName() string {
	return receiver.name
}

func (receiver *expressionDefinition) getDescription() string {
	return receiver.description
}

func (receiver *expressionDefinition) isRequired() bool {
	return receiver.required
}

func (receiver *expressionDefinition) getDefaultValue() string {
	return receiver.defaultValue
}

func (receiver *expressionDefinition) checkValue(value string) (string, bool) {
	if receiver.valueChecker != nil {
		msg, ok := receiver.valueChecker(value)
		if !ok {
			return "表达式(name=" + receiver.name + ")值校验失败: " + msg, false
		} else {
			return msg, true
		}
	} else {
		return "", true
	}
}

// ================================================ utils =======================================================
type number interface {
	int64 | float64
}

type numberRange[T number] struct {
	min T
	max T
}

func (receiver numberRange[T]) createNumberRangeChecker(option *optionDefinition, numberConverter func(string) (T, error)) func(string) (string, bool) {
	if receiver.max < receiver.min {
		panic(option.getKetch() + "创建失败，选项的最小值不能大于最大值")
	}
	return func(value string) (string, bool) {
		tValue, err := numberConverter(value)
		if err != nil {
			return value + "无法转换为" + option.valueType + "类型的值", false
		}
		if tValue < receiver.min {
			return value + "小于最小值", false
		}
		if tValue > receiver.max {
			return value + "小于最小值", false
		}
		return "", true
	}
}

func createIntOptionValueChecker(valueRange func() (int64, int64), option *optionDefinition) func(string) (string, bool) {
	if valueRange == nil {
		return nil
	}
	minValue, maxValue := valueRange()
	return numberRange[int64]{
		min: minValue,
		max: maxValue,
	}.createNumberRangeChecker(option, intParser)
}

func createFloatOptionValueChecker(valueRange func() (float64, float64), option *optionDefinition) func(string) (string, bool) {
	if valueRange == nil {
		return nil
	}
	minValue, maxValue := valueRange()
	return numberRange[float64]{
		min: minValue,
		max: maxValue,
	}.createNumberRangeChecker(option, floatParser)
}

var intParser = func(s string) (int64, error) {
	return strconv.ParseInt(s, 10, 64)
}

var floatParser = func(s string) (float64, error) {
	return strconv.ParseFloat(s, 64)
}
